package com.tc.runner;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.hash.Hash;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tc.constant.RedisConstants;
import com.tc.domain.dataobject.PermissionDO;
import com.tc.domain.dataobject.RoleDO;
import com.tc.domain.dataobject.RolePermissionRelDO;
import com.tc.domain.mapper.PermissionDOMapper;
import com.tc.domain.mapper.RoleDOMapper;
import com.tc.domain.mapper.RolePermissionRelDOMapper;
import com.tc.domain.mapper.UserRoleRelDOMapper;
import com.tc.operationlog.JsonUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.nio.reactor.ssl.PermanentSSLBufferManagementStrategy;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
@Slf4j
public class PushRolePermissions2RedisRunner implements ApplicationRunner {

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private RoleDOMapper roleDOMapper;

    @Resource
    private RolePermissionRelDOMapper rolePermissionRelDOMapper;

    @Resource
    private PermissionDOMapper permissionDOMapper;

    // 权限同步标记 Key
    private static  final String PUSH_PERMISSION_FLAG = "push.permission.flag";

    @Override
    public void run(ApplicationArguments args) {
        log.info("==> 服务启动，开始同步角色权限数据到 Redis 中...");

        try {
            // 添加锁控制 放置集群中多个服务 全部同步数据
            Boolean setBoolean = redisTemplate.opsForValue().setIfAbsent(PUSH_PERMISSION_FLAG, "1", 1, TimeUnit.DAYS);

            // 如果无法同步权限数据
            if (!setBoolean){
                log.warn("==> 角色权限数据已经同步至 Redis中， 不在同步...");
                return;
            }
            // 总的来说 先查角色表 然后 根据角色ID 查关联表 得到每个ID 对应的权限ID  把权限ID 转换成对应的权限实体
            List<RoleDO> roleDOList = roleDOMapper.selectEnabledList();
            List<Long> roleIdList = roleDOList.stream().map(RoleDO::getId).collect(Collectors.toList());
            // 构造ID 权限实体表
            List<PermissionDO> permissionDOS = permissionDOMapper.selectEnabledPermission();
            Map<Long, PermissionDO> permissionDOMap = permissionDOS.stream().collect(Collectors.toMap(PermissionDO::getId, Function.identity()));

            // 根绝角色ID 查关联表 构造一个 角色ID:　权限ID
            List<RolePermissionRelDO> rolePermissionRelDOS = rolePermissionRelDOMapper.selectPermissionByRoleId(roleIdList);
            Map<Long, List<Long>> roleIdPermissionIdMap = rolePermissionRelDOS.stream().collect(Collectors.groupingBy(RolePermissionRelDO::getRoleId,
                    Collectors.mapping(RolePermissionRelDO::getPermissionId, Collectors.toList())));

            // 转换对应的权限实体
            Map<String, List<String>> idToPermissionDO = new HashMap<>();

//            for (RolePermissionRelDO rolePermissionRelDO : rolePermissionRelDOS) {
//                Long roleId = rolePermissionRelDO.getRoleId();
//                Long permissionId = rolePermissionRelDO.getPermissionId();
//
//
//                PermissionDO permissionDO = permissionDOMap.get(permissionId);
//                if (Objects.nonNull(permissionDO)) {
//                    idToPermissionDO.computeIfAbsent(roleId, k -> new ArrayList<>()).add(permissionDO);
//                }
//            }
            roleDOList.forEach(roleDO -> {
                Long roleDOId = roleDO.getId();
                String roleKey = roleDO.getRoleKey();
                // 当前角色对应的权限ID 集合
                List<Long> permissionIds = roleIdPermissionIdMap.get(roleDOId);
                if (CollUtil.isNotEmpty(permissionIds)) {
                    List<String> permissionKeys = Lists.newArrayList();
                    permissionIds.forEach(permissionId -> {
                        // 根据权限 ID 获取具体的权限 DO 对象
                        PermissionDO permissionDO = permissionDOMap.get(permissionId);
                        permissionKeys.add(permissionDO.getPermissionKey());
                    });
                    idToPermissionDO.put(roleKey, permissionKeys);
                }
            });
            log.info("==> 权限数据查看：{}", idToPermissionDO);

            // 同步到redis
            idToPermissionDO.forEach((k, v) -> {
                // 构建参数K
                String rolePermissionKey = RedisConstants.ROLE_PERMISSION_KEY_PREFIX + k;
                redisTemplate.opsForValue().set(rolePermissionKey, JsonUtils.toJsonString(v));
            });
            log.info("==> 服务启动，成功同步角色权限数据到 Redis 中...");
        }catch (Exception e){
            log.error("==> 同步角色权限数据到 Redis 中失败:",e);
        }
    }
}
